﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Windy.OpenLink.Names
{
    public class NameItem
    {
        #region Constructors

        protected NameItem(NameItem parent, NameItem child)
        {
            this.parent = parent;
            this.child = child;
        }

        internal protected NameItem(string name, string extension = null, NameItem child = null)
        {
            if (name == null)
                throw new ArgumentException("name is null", "name");
            this.name = name;

            this.extension = extension;
            Child = child;
        }

        #endregion

        #region Properties

        private NameItem parent;
        public NameItem Parent
        {
            get { return parent; }
            protected set { parent = value; }
        }
        public bool HasParent { get { return Parent != null; } }

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("Name", "Name is null");

                if (!value.VerifyNodePrimaryName())
                    throw NameException.CreateKnownException(NameException.ExceptionReason.InvalidNodePrimaryName);

                name = value;
            }
        }

        private string extension;
        public string Extension
        {
            get { return extension; }
            set
            {
                if (value != null && !value.VerifyExtensionName())
                {
                    throw NameException.CreateKnownException(NameException.ExceptionReason.InvalidNodeExtensionName);
                }

                extension = value;
            }
        }
        public bool HasExtension { get { return Extension != null; } }

        private NameItem child;
        public NameItem Child
        {
            get { return child; }
            set
            {
                if (child == value)
                    return;

                if (child != null)
                {
                    child.parent = null;
                }
                child = value;
                if (child != null)
                {
                    child.parent = this;
                }
            }
        }
        public bool HasChild { get { return Child != null; } }

        #endregion

        #region Overrides

        public override string ToString()
        {
            return this.ToFullName();
        }

        #endregion

        #region Conversion Operation

        public static implicit operator string(NameItem item)
        {
            return item.ToString();
        }

        public static implicit operator NameItem(string text)
        {
            return text.ParseName();
        }

        #endregion

        #region Traversal Members

        public IEnumerable<NameItem> AsChildren() { return new Enumerator(this, true); }

        public IEnumerable<NameItem> AsParents() { return new Enumerator(this, false); }

        #endregion

        #region Nested Types

        protected struct Enumerator : IEnumerable<NameItem>, IEnumerator<NameItem>
        {
            #region Constructor

            public Enumerator(NameItem first, bool directionToChild)
                : this()
            {
                this.Root = new NameItem(first, first);
                this.DirectionToChild = directionToChild;

                Reset();
            }

            #endregion

            #region Enumerator Members

            private NameItem Root;
            private bool DirectionToChild;

            public NameItem Current { get; private set; }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (DirectionToChild)
                {
                    if (Current.HasChild)
                    {
                        Current = Current.Child;
                        return true;
                    }
                    else
                        return false;
                }
                else
                {
                    if (Current.HasParent)
                    {
                        Current = Current.Parent;
                        return true;
                    }
                    else
                        return false;
                }
            }

            public void Reset()
            {
                Current = Root;
            }
            #endregion

            #region IDisposable Members

            public void Dispose() { /* Do Nothing */ }

            #endregion

            #region IEnumerable<NameItem> Members

            public IEnumerator<NameItem> GetEnumerator()
            {
                return this;
            }

            #endregion

            #region IEnumerable Members

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this;
            }

            #endregion
        }

        #endregion
    }
    
}
